#include "nemu.h"
#include "monitor/monitor.h"
#include "monitor/watchpoint.h"
#include "monitor/expr.h"

/* The assembly code of instructions executed is only output to the screen
 * when the number of instructions executed is less than this value.
 * This is useful when you use the `si' command.
 * You can modify this value as you want.
 */
#define MAX_INSTR_TO_PRINT 10

int nemu_state = NEMU_STOP;

void exec_wrapper(bool);

/* Simulate how the CPU works. */
void cpu_exec(uint64_t n) {
  if (nemu_state == NEMU_END) {
    printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
    return;
  }
  nemu_state = NEMU_RUNNING;

  bool print_flag = n < MAX_INSTR_TO_PRINT;

  for (; n > 0; n --) {
    /* Execute one instruction, including instruction fetch,
     * instruction decode, and the actual execution. */
    exec_wrapper(print_flag);

#ifdef DEBUG
    /* TODO: check watchpoints here. */
    // 遍历所有活动的监视点
    WP *wp = get_wp_head();
    while (wp != NULL) {
        bool success = true;
        // 求值监视表达式
        uint32_t new_val = expr(wp->expr, &success);
        if (success && new_val != wp->val) {
            // 监视点触发：输出提示信息
            printf("Watchpoint %d triggered: %s\n", wp->NO, wp->expr);
            printf("Old value = 0x%08x, new value = 0x%08x\n", wp->val, new_val);
            wp->val = new_val;  // 更新旧值
            nemu_state = NEMU_STOP; // 停止程序
            return;  // 退出 cpu_exec() 循环
        }
        wp = wp->next;
    }

#endif

#ifdef HAS_IOE
    extern void device_update();
    device_update();
#endif

    if (nemu_state != NEMU_RUNNING) { return; }
  }

  if (nemu_state == NEMU_RUNNING) { nemu_state = NEMU_STOP; }
}
